
#ifndef __LIBERTY_ENGINE_GAMEOBJECT_H__
#define __LIBERTY_ENGINE_GAMEOBJECT_H__

#include "Object.h"

#include <string>

#include <Liberty3D/Liberty3D.h>

#include <Liberty3D/Engine/ISerializable.h>

#include <Liberty3D/Engine/Context.h>
#include <Liberty3D/Engine/Quaternion.h>
#include <Liberty3D/Engine/Vector3.h>

namespace Liberty { namespace Engine {
    class GameObject : public Object, public std::enable_shared_from_this<GameObject>, public ISerializable {
        friend class Context;

    protected:
        std::weak_ptr<Context>    _context;
        std::weak_ptr<GameObject> _parent;
        std::string               _name;
        Vector3                   _localPosition;
        Quaternion                _localRotation;
        Vector3                   _localScale;
        bool                      _active;
        int                       _layer;
        unsigned int              _tag;

    protected:
        GameObject(const std::shared_ptr<Context>& context, const std::string& name);

    public:
        virtual std::string name() const;
        virtual void setName(const std::string& name);

    public:
        std::shared_ptr<Context>    context() const { return _context.lock(); }
        std::shared_ptr<GameObject> parent()  const { return _parent.lock(); }
        void setParent(const std::shared_ptr<GameObject>& gameObject);

        inline const Vector3&    localPosition() const { return _localPosition; }
        inline const Quaternion& localRotation() const { return _localRotation; }
        inline const Vector3&    localScale()    const { return _localScale; }

        inline bool active() const { return _active; }
        inline int layer()   const { return _layer; }
        inline int tag()     const { return _tag; }

        void setActive(bool);
        void setLayer(int);
        void setTag(int);

        std::shared_ptr<Component> addComponent(const std::string&);

        template <typename T> std::shared_ptr<T> addComponent() {
            std::shared_ptr<T> c(new T());

            context()->addComponent(shared_from_this(), c);
            return c;
        }

    public: // ISerializable
        virtual void serializeObject(ISerializer*);
        virtual const char* serializeClassName() const;
        virtual void serializeEnd(ISerializer*);
    };
}}

#endif
